package com.yswee.framework.net.http;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

import com.google.gson.Gson;
import com.yswee.framework.Application;
import com.yswee.framework.data.parser.IParser;
import com.yswee.framework.utils.FileUtils;
import com.yswee.framework.utils.HttpUtils;

import android.net.Uri;


public class Entity<TPARSED> extends com.yswee.framework.net.Entity {

	private static final long serialVersionUID = 528889795769392217L;
		
	protected HttpType httptype = HttpType.Get;
	
	/**
	 * 设置http类型
	 * @param value
	 */
	public void setHttpType(HttpType value) {
		httptype = value;
	}
	
	/**
	 * http类型
	 * @return
	 */
	public HttpType getHttpType() {
		return httptype;
	}
	
	protected IParser<TPARSED> parser;
	
	/**
	 * 设置解析器
	 * @param parser
	 */
	public void setParser(IParser<TPARSED> parser) {
		this.parser = parser;
	}
	
	/**
	 * 获取解析器
	 * @return
	 */
	public IParser<TPARSED> getParser() {
		return this.parser;
	}
	
	protected boolean urlEncode = true;
	
	/**
	 * 设置post的数据是否urlencode
	 * @param urlEncode
	 */
	public void setUrlEncode(boolean urlEncode) {
		this.urlEncode = urlEncode;
	}
	
	/**
	 * 获取post的数据是否urlencode
	 * @return
	 */
	public boolean getUrlEncode() {
		return this.urlEncode;
	}
	
	/**
	 * 设置消息体
	 * @param message
	 */
	void setMessage(String message) {
		this.message = message;
	}
	
	private GetType getType;
	/**
	 * Get类型
	 * @return
	 */
	public GetType getGetType() {
		return getType;
	}

	/**
	 * 设置Get类型
	 * @param httpType
	 */
	public void setGetType(GetType httpType) {
		this.getType = httpType;
	}

	private PostType postType;

	/**
	 * Post类型
	 * @return
	 */
	public PostType getPostType() {
		return postType;
	}

	/**
	 * 设置Post类型
	 * @param httpType
	 */
	public void setPostType(PostType httpType) {
		this.postType = httpType;
	}
	
	private String boundary = "-------------------37531613912423";
	
	/**
	 * Post的Boundary
	 * @return
	 */
	public String getBoundary() {
		return boundary;
	}

	/**
	 * 设置Post的Boundary
	 * @param boundary
	 */
	public void setBoundary(String boundary) {
		this.boundary = boundary;
	}

	private HashMap<String, Object> postData;
	
	/**
	 * Post的数据
	 * @return
	 */
	public HashMap<String, Object> getPostData() {
		return postData;
	}

	/**
	 * 设置Post的数据
	 * @param postData
	 */
	public void setPostData(HashMap<String, Object> postData) {
		this.postData = postData;
	}
	
	private long totalDownloadSize;
	
	/**
	 * 下载总字节大小
	 * @return
	 */
	public long getTotalDownloadSize() {
		return totalDownloadSize;
	}
	
	private long curentDownloadSize;

	/**
	 * 已下载字节大小
	 * @return
	 */
	public long getCurrentDownloadSize() {
		return curentDownloadSize;
	}

	/**
	 * 设置下载进度
	 * @param curentSize
	 * @param totalSize
	 */
	void setDownloadProgress(long curentSize, long totalSize) {
		this.curentDownloadSize = curentSize;
		this.totalDownloadSize = totalSize;
	}
	
	private long totalUploadSize;
	
	/**
	 * 上传总字节大小
	 * @return
	 */
	public long getTotalUploadSize() {
		return totalUploadSize;
	}
	
	private long curentUploadSize;

	/**
	 * 已上传字节大小
	 * @return
	 */
	public long getCurrentUploadSize() {
		return curentUploadSize;
	}

	/**
	 * 设置上传进度
	 * @param curentSize
	 * @param totalSize
	 */
	void setUploadProgress(long curentSize, long totalSize) {
		this.curentUploadSize = curentSize;
		this.totalUploadSize = totalSize;
	}
	
	private TPARSED parsedData;
	
	/**
	 * 解析Response后的数据
	 * @return
	 */
	public TPARSED getParsedData() {
		return parsedData;
	}

	/**
	 * 设置解析后的数据
	 * @param parsedData
	 */
	public void setParsedData(TPARSED parsedData) {
		this.parsedData = parsedData;
	}
	
	private byte[] responseData;
	
	/**
	 * Response的字节流
	 * @return
	 */
	public byte[] getResponseData() {
		return responseData;
	}

	/**
	 * 设置Reponse的字节流
	 * @param responseData
	 */
	public void setResponseData(byte[] responseData) {
		this.responseData = responseData;
	}
	
	public Entity() {
		super();
	}

	private int postLength;
	private ArrayList<Object> postBytes;

	/**
	 * 转换成byte后的post数据
	 * @return
	 */
	public ArrayList<Object> getPostBytes() {
		if (postBytes == null) {
			transferPostBytes();
		}
		return postBytes;
	}
	
	/**
	 * 获取Post数据的长度
	 * @return
	 */
	public int getContentLength() {
		if(postLength == 0) {
			transferPostBytes();
			if(postBytes != null) {
				for(int i = 0; i < postBytes.size(); i++) {
					Object value = postBytes.get(i);
					if(value != null) {
						if(value instanceof byte[]) {
							byte[] bytes = (byte[]) value;
							if(bytes != null) {
								postLength += bytes.length;
							}
						} else if(value instanceof Uri) {
							Uri uri = (Uri) value;
							if(uri != null) {
								postLength += FileUtils.getFileLength(
									Application.get(), uri);
							}
						}
					}
				}
			}
		}
		return postLength;
	}
	
	protected void transferPostBytes() {
		try {
			if(httptype == HttpType.Post) {
				postBytes = new ArrayList<Object>();
				if(getPostType() == PostType.MULTIPART) {
					writeMultiple();
				} else if(getPostType() == PostType.JSON) {
					writeJson();
				} else if(getPostType() == PostType.BYTES) {
					writeBytes();
				} else {
					writeString();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	protected void writeBytes() throws IOException {
        if (postData != null && postData.size() > 0) {
	        Iterator<Entry<String, Object>> iter = postData.entrySet().iterator(); 
	        while (iter.hasNext()) { 
	            Entry<String, Object> element = (Entry<String, Object>) iter.next();
	            if(element.getValue() != null) {
	            	Object value = element.getValue();
            		if(value instanceof byte[]) {
		            	byte[] bytes = (byte[]) value;
		            	if(bytes != null && bytes.length > 0) {
		            		postBytes.add(value);
		            	}
	            	} else if(value instanceof Uri) {
	            		postBytes.add(value);
	            	}
	            }
	        }
        }
    }
	
	protected void writeJson() throws IOException {
        if (postData == null) {
        	postData = new HashMap<String, Object>();
        }
        Gson gson = new Gson();
        postBytes.add(gson.toJson(postData).getBytes());
    }
	
	@SuppressWarnings("unchecked")
	protected void writeString() throws IOException {  
        if (postData != null && postData.size() > 0) {
            StringBuffer context = new StringBuffer();
	        Iterator<Entry<String, Object>> iter = postData.entrySet().iterator(); 
	        String key = null, value = null;
	        ArrayList<String> values = new ArrayList<String>();
	        while (iter.hasNext()) { 
	            Entry<String, Object> element = (Entry<String, Object>) iter.next();
	            if(element.getKey() == null) {
	            	key = "";
	            } else {
	            	key = element.getKey().toString();
	            }
	            values.clear();
	            if(element.getValue() == null) {
            		value = "";
            		values.add(value);
	            } else {
	            	if (element.getValue() instanceof ArrayList<?>) {
	            		for (int i = 0; i < ((ArrayList<String>) element.getValue()).size(); i++) {
		            		value = ((ArrayList<String>) element.getValue()).get(i);
		            		values.add(value);
	            		}
	            	} else if (element.getValue() instanceof String[]) {
	            		for (int i = 0; i < ((String[]) element.getValue()).length; i++) {
		            		value = ((String[]) element.getValue())[i];
		            		values.add(value);
	            		}
	            	} else {
	            		value = element.getValue().toString();
	            		values.add(value);
	            	}
	            }
	            for (int i = 0; i < values.size(); i++) {
            		value = values.get(i);
            		context.append(key).append("=");
		        	if(urlEncode) {
		        		context.append(URLEncoder.encode(value, "utf-8"));
		        	} else {
		        		context.append(value);
		        	}
		        	context.append("&");
        		}
	        }
	        if (context.toString().length() > 0) {
	            context.setLength(context.length() - 1);
	            value = context.toString();
	            byte bytes[] = new byte[value.length()];
	            for (int index = 0; index < value.length(); index++) {
	                bytes[index] = (byte) value.charAt(index);
	            }
        		postBytes.add(bytes);
	        }
        }
    }

    @SuppressWarnings("unchecked")
	protected void writeMultiple() throws IOException {
        if (postData != null && postData.size() > 0) {
	        String key = null;
	        Object value = null;
            Iterator<Entry<String, Object>> iter = postData.entrySet().iterator(); 
            while (iter.hasNext()) { 
                Entry<String, Object> element = (Entry<String, Object>) iter.next();
                if(element.getKey() == null) {
	            	key = "";
	            } else {
	            	key = element.getKey().toString();
	            }
                value = element.getValue();
	            if(value != null) {
		        	if(value instanceof byte[]) {
	            		postBytes.add(createImageField(key, (byte[])value));
					} else if(value instanceof Uri) {
	            		postBytes.add(writeUriFieldBegin(key, (Uri)value));
	            		postBytes.add(value);
	            		postBytes.add(writeUriFieldEnd());
					} else if (value instanceof ArrayList<?>) {
						for (int i = 0; i < ((ArrayList<String>) value).size(); i++) {
		            		postBytes.add(createStringField(key, ((ArrayList<String>) value).get(i)));
	            		}
					} else if (value instanceof String[]) {
						for (int i = 0; i < ((String[]) value).length; i++) {
		            		postBytes.add(createStringField(key, ((String[]) value)[i]));
	            		}
		        	} else {
	            		postBytes.add(createStringField(key, value.toString()));
		        	}
	            } else {
	            	postBytes.add(createStringField(key, ""));
	            }
	        }
	        byte[] bend = createEndField();
    		postBytes.add(bend);
        }
    }

    protected byte[] createStringField(String fieldName, String fieldValue) throws UnsupportedEncodingException {
        StringBuilder sb = new StringBuilder();
        sb.append("--" + getBoundary());
        sb.append("\r\n");
        sb.append("Content-Disposition: form-data; name=\"" + fieldName + "\"");
        sb.append("\r\n");
        sb.append("\r\n");
        if(urlEncode) {
        	sb.append(URLEncoder.encode(fieldValue, "utf-8"));
        } else {
        	sb.append(fieldValue);
        }
        sb.append("\r\n");
        byte[] data = sb.toString().getBytes("utf-8");
        return data;
    }

    protected byte[] writeUriFieldBegin(String fieldName, Uri uri) throws IOException {
    	String filename = fieldName;
    	String contenttype = HttpUtils.CONTENTTYPE_JPEG;
    	try {
	    	String path = uri.getPath();
	    	filename = path.substring(path.lastIndexOf("/") + 1);
	    	contenttype = HttpUtils.getContentType(filename);
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    	StringBuilder sb = new StringBuilder();
        sb.append("--" + getBoundary());
        sb.append("\r\n");
        sb.append("Content-Disposition: form-data; name=\"").append(fieldName).
					append("\"; filename=\"").append(filename).append("\"");
        sb.append("\r\n");
        sb.append("Content-Type: ").append(contenttype);
        sb.append("\r\n");
        sb.append("\r\n");
        byte[] dataBegin = sb.toString().getBytes("utf-8");
        return dataBegin;
    }
    
    protected byte[] writeUriFieldEnd() throws IOException {
        byte[] dataEnd = ("\r\n").getBytes("utf-8");
        return dataEnd;
    }

    protected byte[] createImageField(String fieldName, byte[] dataPic) throws UnsupportedEncodingException {
    	String name = fieldName;
    	String filename = fieldName;
    	String contenttype = HttpUtils.CONTENTTYPE_JPEG;
    	if(name.indexOf(".") >= 0) {
    		name = name.substring(0, name.lastIndexOf("."));
    		contenttype = HttpUtils.getContentType(name);
    	} else {
    		filename = filename + ".jpg";
    	}
        StringBuilder sb = new StringBuilder();
        sb.append("--" + getBoundary());
        sb.append("\r\n");
        sb.append("Content-Disposition: form-data; name=\"").append(name).
        			append("\"; filename=\"").append(filename).append("\"");
        sb.append("\r\n");
        sb.append("Content-Type: ").append(contenttype);
        sb.append("\r\n");
        sb.append("\r\n");
        byte[] dataBegin = sb.toString().getBytes("utf-8");
        byte[] dataEnd = ("\r\n").getBytes("utf-8");

        byte[] data = new byte[dataBegin.length + dataPic.length + dataEnd.length];
        System.arraycopy(dataBegin, 0, data, 0, dataBegin.length);
        System.arraycopy(dataPic, 0, data, dataBegin.length, dataPic.length);
        System.arraycopy(dataEnd, 0, data, dataBegin.length + dataPic.length, dataEnd.length);
        return data;
    }

    protected byte[] createEndField() throws IOException {
        StringBuilder sb = new StringBuilder();
        sb.append("--" + getBoundary() + "--");
        sb.append("\r\n");
        byte[] data = sb.toString().getBytes("utf-8");
        return data;
    }
}
